﻿using System;
using System.Collections.Generic;
using System.Data.OleDb;
using System.Linq;
using System.Security.Principal;
using System.ServiceModel;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using Ensynch;
using Ensynch.FIM;
using Microsoft.ReportingServices.DataProcessing;
using Microsoft.ResourceManagement.Client;
using Microsoft.ResourceManagement.Client.WsTransfer;
using Microsoft.ResourceManagement.ObjectModel;
using Microsoft.ResourceManagement.ObjectModel.ResourceTypes;

namespace FimDataProcessingExtension
{
    public sealed class FimDataReader : IDataReader
    {
        // Create a logger for use in this class.
        private static readonly log4net.ILog log = log4net.LogManager.GetLogger(
                System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        #region Variables

        private FimConnection connection;
        private FimQuery query;

        //private DefaultClient m_defaultClient;
        //private MexClient m_ClientMexClient;
        //private string m_WhereClause = "";
        //internal List<RmResource> m_rmResources = new List<RmResource>();
        //internal System.Data.DataTable m_DataTable = new System.Data.DataTable();
        //internal System.Data.DataView m_DataView;
        //internal Boolean m_tableRead = false;
        //internal int m_currentRow = -1;
        //internal IEnumerable<RmResource> m_Enumerator;
        //internal int m_rowIndex;
        //internal int? m_maxRows;

        #endregion

        #region Constructors
        /*
        * Because the user should not be able to directly create a 
        * DataReader object, the constructors are
        * marked as internal.
        */
        internal FimDataReader()
        {
            // TODO: Implement default constructor
            throw new NotImplementedException();
        }

        internal FimDataReader(FimQuery query, FimConnection connection)
        {
            this.connection = connection;
            this.query = query;
        }

        #endregion

        #region added properties

        private FimQueryResult result;
        private FimQueryResult Result
        {
            get
            {
                connection.MaybeImpersonate();
                if (result == null)
                {
                    result = query.GetResult();
                }
                return result;
            }
        }

        #endregion

        #region IDataReader members

        /// <summary>
        /// Reads one row after the other. Advances the IDataReader to the next record.
        /// The DataReader object enables a client to retrieve a read-only, forward-only stream of data 
        /// from a data source. Results are returned as the query executes and are stored in the network buffer 
        /// on the client until you request them using the Read method of the DataReader class
        /// </summary>
        /// <returns></returns>
        bool IDataReader.Read()
        {
            try
            {
                return Result.Read();
            }
            catch (Exception exc)
            {
                log.Error("[IDataReader.Read]", exc);
                throw;
            }
        }
        
        /// <summary>
        /// Returns the total number of columns. Gets the number of fields in the data reader.
        /// </summary>
        int IDataReader.FieldCount
        {
            get
            {
                try
                {
                    FimTools.LogTrace(false);

                    return Result.DataTable.Columns.Count;
                }
                catch (Exception exc)
                {
                    log.Error("[IDataReader.FieldCount]", exc);
                    throw;
                }
            }
        }

        /// <summary>
        /// Returns the Datatype of the specified column.
        /// </summary>
        /// <param name="fieldIndex"></param>
        /// <returns></returns>
        Type IDataReader.GetFieldType(int fieldIndex)
        {
            try
            {
                FimTools.LogTrace(false);

                return Result.DataTable.Columns[fieldIndex].DataType;
            }
            catch (Exception exc)
            {
                log.Error("[IDataReader.GetFieldType]", exc);
                throw;
            }
        }

        /// <summary>
        /// Gets the name of the field to find.
        /// </summary>
        /// <param name="fieldIndex"></param>
        /// <returns></returns>
        string IDataReader.GetName(int fieldIndex)
        {
            try
            {
                FimTools.LogTrace(false);

                return Result.DataTable.Columns[fieldIndex].ColumnName;
            }
            catch (Exception exc)
            {
                log.Error("[IDataReader.GetName]", exc);
                throw;
            }
        }

        /// <summary>
        /// Return the index of the named field.
        /// </summary>
        /// <param name="fieldName"></param>
        /// <returns></returns>
        int IDataReader.GetOrdinal(string fieldName)
        {
            try
            {
                FimTools.LogTrace(false);

                if (!Result.DataTable.Columns.Contains(fieldName))
                {
                    throw new IndexOutOfRangeException(string.Format(@"""{0}"" column not found.", fieldName));
                }
                return Result.DataTable.Columns[fieldName].Ordinal;
            }
            catch (Exception exc)
            {
                log.Error("[IDataReader.GetOrdinal]", exc);
                throw;
            }
        }

        /// <summary>
        /// Return the value of the specified field.
        /// </summary>
        /// <param name="fieldIndex"></param>
        /// <returns></returns>
        object IDataReader.GetValue(int fieldIndex)
        {
            try
            {
                FimTools.LogTrace(false);

                //return m_DataView[m_currentRow].Row[fieldIndex];
                return Result.CurrentRow[fieldIndex];
            }
            catch (Exception exc)
            {
                log.Error("[IDataReader.GetValue]", exc);
                throw;
            }
        }

        #endregion

        #region Dispose

        void IDisposable.Dispose()
        {
            if (Result != null)
            {
                Result.Dispose();
            }
        }

        #endregion

        /// <summary>
        /// Insert parameters into an ADO.net filter string.
        /// </summary>
        //private void insertADOParametersIntoWhereClause()
        //{
        //    if (m_Parameters.Count > 0)
        //    {
        //        foreach (FimDataParameter oParam in m_Parameters)
        //        {
        //            string name = ((IDataParameter)oParam).ParameterName;
        //            if (!name.StartsWith("@"))
        //                throw new Exception("Invalid Parameter Name \"" + name + "\". The name must start with a \"@\"");

        //            System.Data.DataColumn oCol = m_DataTable.Columns[name.Substring(1)];
        //            string typeName = "asis";
        //            string valueString = "";
        //            if (oCol != null)
        //            {
        //                typeName = oCol.DataType.Name.ToLower();
        //            }
        //            switch (typeName)
        //            {
        //                case "string":
        //                    valueString = "'" + ((IDataParameter)oParam).Value.ToString() + "'";
        //                    break;
        //                case "int":
        //                    valueString = ((IDataParameter)oParam).Value.ToString();
        //                    break;
        //                case "datetime":
        //                    valueString = "'" + ((IDataParameter)oParam).Value.ToString() + "'";
        //                    break;
        //                case "boolean":
        //                    if ((Boolean)((IDataParameter)oParam).Value)
        //                        valueString = "1";
        //                    else
        //                        valueString = "0";
        //                    break;
        //                case "asis":
        //                    valueString = ((IDataParameter)oParam).Value.ToString();
        //                    break;
        //                case "buffer":
        //                default:
        //                    throw new Exception("Parameter \"" + name + "\" is an invalid type. \"" + typeName + "\" is not valid in a query.");
        //            }
        //            m_WhereClause = m_WhereClause.Replace(name, valueString);
        //        }
        //    }
        //}

        /// <summary>
        /// Insert parameters into a XPATH string.
        /// </summary>
        /// <param name="_commandString"></param>
        /// <returns></returns>
        //private string insertParametersIntoXPATHQuery(string _commandString)
        //{
        //    if (m_Parameters.Count > 0)
        //    {
        //        foreach (FimDataParameter oParam in m_Parameters)
        //        {
        //            string name = ((IDataParameter)oParam).ParameterName;
        //            if (!name.StartsWith("#"))
        //                throw new Exception("Invalid XPATH Parameter Name \"" + name + "\". The name must start with a \"#\"");

        //            System.Data.DataColumn oCol = m_DataTable.Columns[name.Substring(1)];
        //            string typeName = "asis";
        //            string valueString = "";
        //            if (oCol != null)
        //            {
        //                typeName = oCol.DataType.Name.ToLower();
        //            }
        //            switch (typeName)
        //            {
        //                case "string":
        //                    valueString = "\"" + ((IDataParameter)oParam).Value.ToString() + "\"";
        //                    break;
        //                case "int":
        //                    valueString = ((IDataParameter)oParam).Value.ToString();
        //                    break;
        //                case "datetime":
        //                    valueString = "\"" + ((IDataParameter)oParam).Value.ToString() + "\"";
        //                    break;
        //                case "boolean":
        //                    if ((Boolean)((IDataParameter)oParam).Value)
        //                        valueString = "1";
        //                    else
        //                        valueString = "0";
        //                    break;
        //                case "asis":
        //                    valueString = ((IDataParameter)oParam).Value.ToString();
        //                    break;
        //                case "buffer":
        //                default:
        //                    throw new Exception("Parameter \"" + name + "\" is an invalid type. \"" + typeName + "\" is not valid in a query.");
        //            }
        //            _commandString = _commandString.Replace(name, valueString);
        //        }
        //    }
        //    //
        //    // Return a string where XML characters have been replaced with their encoded values
        //    //
        //    _commandString = _commandString.Replace("&", "&amp;");

        //    ///
        //    /// TODO: figure out why we do the replace below
        //    ///     NOTE: (by Craig) it breaks XPath queries that use datetime functions
        //    ///     
        //    ///return _commandString.Replace("<", "&lt;").Replace(">", "&gt;");
            
        //    return _commandString;
        //}

    }
}
